package de.osmembrane.tools.xmlocalizr;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

public class ViewFrame extends JFrame {

	private static final long serialVersionUID = 1444895654150081303L;

	/**
	 * Model of the JTree
	 */
	private DefaultTreeModel treeModel;

	/**
	 * Document of the JDOM XML Parser
	 */
	private Document xmlDoc;

	/**
	 * File chooser for open/save
	 */
	private JFileChooser fileChooser;

	/**
	 * Top & bottom textarea for editing the content.
	 */
	private JTextArea upper, lower;

	/**
	 * Top & bottom language keys for editing the content
	 */
	private String upperLang, lowerLang;

	/**
	 * JTree to display nodes
	 */
	private JTree xmlTree;

	/**
	 * LangChooser Dialog
	 */
	private SelectLangDialog sld;

	/**
	 * Creates a new {@link ViewFrame}.
	 */
	public ViewFrame() {
		setTitle("XMLocalizr"); //$NON-NLS-1$

		makeMenuBar();

		getContentPane().setLayout(new GridLayout(1, 1));
		treeModel = new DefaultTreeModel(new DefaultMutableTreeNode(
				I18N.getString("ViewFrame.StartNode"))); //$NON-NLS-1$
		xmlTree = new JTree(treeModel);
		xmlTree.addTreeSelectionListener(new TreeSelectionListener() {

			@Override
			public void valueChanged(TreeSelectionEvent e) {
				upper.setEnabled(false);
				lower.setEnabled(false);

				if ((e.getNewLeadSelectionPath() != null)
						&& (e.getNewLeadSelectionPath().getLastPathComponent() != null)) {

					DefaultMutableTreeNode lastPath = (DefaultMutableTreeNode) e
							.getNewLeadSelectionPath().getLastPathComponent();
					if (lastPath.getUserObject() instanceof XMLTreeObject) {
						selected((XMLTreeObject) lastPath.getUserObject());
					}

				}
			}
		});

		JPanel localizer = new JPanel();
		localizer.setLayout(new GridLayout(2, 1));

		lower = new JTextArea();
		lower.setEnabled(false);
		lower.setLineWrap(true);
		lower.setWrapStyleWord(true);

		upper = new JTextArea();
		upper.setEnabled(false);
		upper.setLineWrap(true);
		upper.setWrapStyleWord(true);

		localizer.add(new JScrollPane(upper));
		localizer.add(new JScrollPane(lower));

		JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
				new JScrollPane(xmlTree), localizer);
		splitter.setDividerLocation(0.5);

		getContentPane().add(splitter);

		fileChooser = new JFileChooser("."); //$NON-NLS-1$
		fileChooser.setFileFilter(new FileFilter() {

			@Override
			public String getDescription() {
				return I18N.getString("ViewFrame.XMLFilesFilter"); //$NON-NLS-1$
			}

			@Override
			public boolean accept(File f) {
				return f.getAbsolutePath().toLowerCase().endsWith(".xml") //$NON-NLS-1$
						|| f.isDirectory();
			}
		});

		setPreferredSize(new Dimension(800, 500));
		pack();
		XMLocalizr.centerWindow(this);

		sld = new SelectLangDialog();
		sld.setVisible(true);
		upperLang = sld.getUpperLang();
		lowerLang = sld.getLowerLang();
	}

	/**
	 * Makes the menu bar.
	 */
	private void makeMenuBar() {
		setJMenuBar(new JMenuBar());

		// File
		JMenu fileMenu = new JMenu(I18N.getString("ViewFrame.FileMenu")); //$NON-NLS-1$

		JMenuItem fileOpen = new JMenuItem(I18N.getString("ViewFrame.FileOpen")); //$NON-NLS-1$
		fileOpen.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (fileChooser.showOpenDialog(ViewFrame.this) == JFileChooser.APPROVE_OPTION) {
					loadXML(fileChooser.getSelectedFile());
				}
			}
		});
		fileMenu.add(fileOpen);

		JMenuItem fileSave = new JMenuItem(I18N.getString("ViewFrame.FileSave")); //$NON-NLS-1$
		fileSave.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (fileChooser.showSaveDialog(ViewFrame.this) == JFileChooser.APPROVE_OPTION) {
					saveXML(fileChooser.getSelectedFile());
				}
			}
		});
		fileMenu.add(fileSave);

		fileMenu.add(new JSeparator());

		JMenuItem fileExit = new JMenuItem(I18N.getString("ViewFrame.FileExit")); //$NON-NLS-1$
		fileExit.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		fileMenu.add(fileExit);

		getJMenuBar().add(fileMenu);

		// Data
		JMenu dataMenu = new JMenu(I18N.getString("ViewFrame.DataMenu")); //$NON-NLS-1$

		JMenuItem dataTrim = new JMenuItem(I18N.getString("ViewFrame.DataTrim")); //$NON-NLS-1$
		dataTrim.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit
				.getDefaultToolkit().getMenuShortcutKeyMask()));
		dataTrim.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				final String regexPattern = "(\\s+)"; //$NON-NLS-1$
				final String regexReplace = " "; //$NON-NLS-1$
				lower.setText(lower.getText()
						.replaceAll(regexPattern, regexReplace).trim());
				upper.setText(upper.getText()
						.replaceAll(regexPattern, regexReplace).trim());
			}
		});
		dataMenu.add(dataTrim);

		JMenuItem dataApply = new JMenuItem(I18N.getString("ViewFrame.DataApply")); //$NON-NLS-1$
		dataApply.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, Toolkit
				.getDefaultToolkit().getMenuShortcutKeyMask()));
		dataApply.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				DefaultMutableTreeNode lastPath = (DefaultMutableTreeNode) xmlTree
						.getSelectionPath().getLastPathComponent();
				if (lastPath.getUserObject() instanceof XMLTreeObject) {
					XMLTreeObject node = (XMLTreeObject) lastPath
							.getUserObject();
					node.setLocalization(upperLang, upper.getText());
					node.setLocalization(lowerLang, lower.getText());
					node.updateDocument();
				}
			}
		});
		dataMenu.add(dataApply);

		getJMenuBar().add(dataMenu);

		// Settings
		JMenu settingsMenu = new JMenu(I18N.getString("ViewFrame.SettingsMenu")); //$NON-NLS-1$

		JMenuItem setSelectLang = new JMenuItem(I18N.getString("ViewFrame.SettingsSelectLang")); //$NON-NLS-1$
		setSelectLang.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				sld.setVisible(true);
				lowerLang = sld.getLowerLang();
				upperLang = sld.getUpperLang();
			}
		});
		settingsMenu.add(setSelectLang);

		getJMenuBar().add(settingsMenu);

	}

	/**
	 * Loads an XML file from selectedFile.
	 * 
	 * @param selectedFile
	 */
	protected void loadXML(File selectedFile) {
		try {
			xmlDoc = new SAXBuilder().build(selectedFile);

			DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(
					selectedFile.getName());
			treeModel.setRoot(rootNode);
			addXMLTree(rootNode, xmlDoc.getRootElement());

			// expand all
			int row = 0;
			while (row < xmlTree.getRowCount()) {
				xmlTree.expandRow(row);
				row++;
			}

			validate();

		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Recursive function to add all children of elt to anchor.
	 * 
	 * @param anchor
	 *            JTree node below which elements will be added
	 * @param elt
	 *            JDOM node below which elements are read
	 */
	private void addXMLTree(DefaultMutableTreeNode anchor, Element elt) {
		for (Object o : elt.getChildren()) {
			if (o instanceof Element) {
				Element child = (Element) o;

				if (child.getName() != "description") { //$NON-NLS-1$
					DefaultMutableTreeNode belowAnchor = new DefaultMutableTreeNode(
							new XMLTreeObject(child));

					anchor.add(belowAnchor);
					addXMLTree(belowAnchor, child);
				}
			}
		} /* for */
	}

	/**
	 * Saves an XML file to selectedFile.
	 * 
	 * @param selectedFile
	 */
	protected void saveXML(File selectedFile) {
		try {
			new XMLOutputter().output(xmlDoc,
					new FileOutputStream(selectedFile));

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Called when an {@link XMLTreeObject} got selected.
	 * 
	 * @param xmlObj
	 */
	protected void selected(XMLTreeObject xmlObj) {
		upper.setEnabled(true);
		lower.setEnabled(true);
		String upLoc = xmlObj.getLocalization(upperLang);
		String lwLoc = xmlObj.getLocalization(lowerLang);

		upper.setText((upLoc != null) ? upLoc : ""); //$NON-NLS-1$
		lower.setText((lwLoc != null) ? lwLoc : ""); //$NON-NLS-1$
	}

}
